<?php

//会员模型

class User_model extends S_Model {

	//密码加密使用的KEY，换的时候需要设置user表password_need_reset为1通知用户需要换密码
	protected $password_key = 'jkjUfjk300fdJFdladk';
	
	public function __construct()
	{
		parent::__construct();
	}
	
	//会员注册（用户名，密码，邮箱，注册来源ID，验证码）
	public function register($username, $password, $email, $source = '', $verify = '')
	{
		$this->load->helper('validation');
		
		$username = trim($username);
		$password = trim($password);
		$email = trim($email);
		$source = trim($source);
		
		//字段合法性验证
		if ($username == '')
		{
			$this->set_error('用户名必须填写！');
			return FALSE;
		}
		elseif ( ! preg_match('/^[a-z0-9_]{1,20}$/i', $username))
		{
			$this->set_error('用户名必须由数字、字母、下划线组成！不得超过20个字符！');
			return FALSE;
		}
		elseif ($password == '')
		{
			$this->set_error('密码必须填写！');
			return FALSE;
		}
		elseif ( ! preg_match('/^[^\s]{6,20}$/', $password))
		{
			$this->set_error('密码必须由6-20个非空字符组成！');
			return FALSE;
		}
		elseif ($email == '')
		{
			$this->set_error('邮箱必须填写！');
			return FALSE;
		}
		elseif ( ! is_email($email))
		{
			$this->set_error('邮箱格式错误！');
			return FALSE;
		}
		
		//验证码验证
		$register_verify = $this->session->get('register_verify');
		$this->session->delete('register_verify');
		if ($register_verify && $register_verify != md5($verify))
		{
			$this->set_error('验证码错误！');
			return FALSE;
		}
		
		//用户名、邮箱唯一性验证
		if ( ! $this->is_username_available($username))
		{
			$this->set_error('用户名已经被注册！');
			return FALSE;
		}
		
		if ( ! $this->is_email_available($email))
		{
			$this->set_error('邮箱已经被注册！');
			return FALSE;
		}
		
		//注册信息写入数据库
		$password = $this->password_hash($password);
		
		$user_data = array(
			'username' => $username,
			'password' => $password,
			'email' => $email
		);
		
		$this->load->model('user_register_model');
		$user_register_data = array(
			'user_id' => 0,
			'ip' => ip_address(),
			'time' => date('Y-m-d H:i:s'),
			'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
			'source' => $source
		);
		
		$this->db->trans_begin();
		
		try
		{
			$id = $this->user_model->insert($user_data);
			
			if ( ! $id)
			{
				log_message('error', '用户名'.$username.'注册失败。原因：写入user表失败。');
				throw new Exception('注册失败！请与管理员联系！');
			}
			
			$user_register_data['user_id'] = $id;
			if ( ! $this->user_register_model->insert($user_register_data))
			{
				log_message('error', '用户名'.$username.'注册失败。原因：写入user_register表失败。');
				throw new Exception('注册失败！请与管理员联系！');
			}
			
			$this->db->trans_commit();
		}
		catch (Exception $e)
		{
			$this->db->trans_rollback();
			$this->set_error($e->getMessage());
			return FALSE;
		}
		
		//发送激活邮件
		$this->send_activate_email($id);
		
		return TRUE;
	}
	
	//登录（用户名，密码，验证码）
	public function login($username, $password, $verify = '')
	{
		$username = trim($username);
		$password = trim($password);
		$verify = strtolower(trim($verify));
		
		//字段验证
		if ($username == '')
		{
			$this->set_error('用户名必须填写！');
			return FALSE;
		}
		elseif ( ! preg_match('/^[a-z0-9_]{1,20}$/i', $username))
		{
			$this->set_error('用户名必须由数字、字母、下划线组成！不得超过20个字符！');
			return FALSE;
		}
		elseif ($password == '')
		{
			$this->set_error('密码必须填写！');
			return FALSE;
		}
		elseif ( ! preg_match('/^[^\s]{6,20}$/', $password))
		{
			$this->set_error('用户名密码错误！');
			return FALSE;
		}
		
		//验证码判断
		$login_verify = $this->session->get('login_verify');
		$this->session->delete('login_verify');
		//若果session中存在登录验证码，则进行验证。当然，login_verify生成的时候是没有时间限制的
		if ($login_verify && $login_verify != md5($verify))
		{
			$this->set_error('验证码错误！');
			return FALSE;
		}
		
		//账号信息判断
		$user_data = $this->get_one(array('username' => $username), array('id', 'email', 'password', 'banned', 'activated', 'password_need_reset'));
		
		if ( ! $user_data)
		{
			$this->set_error('用户名密码错误！');
			return FALSE;
		}
		elseif ($user_data['banned'] == 1)
		{
			$this->set_error('账号已经被禁用！如有疑问，请联系管理员！');
			return FALSE;
		}
		elseif ($user_data['password_need_reset'] == 1)
		{
			$this->set_error('账号密码需要重置！密码重置邮件已经发送到您邮箱中！');
			return FALSE;
		}
		elseif ($user_data['password'] != $this->password_hash($password))
		{
			$this->set_error('用户名密码错误！');
			return FALSE;
		}
		
		$this->load->model('user_login_model');
		
		$user_login_data = array(
			'user_id' => $user_data['id'],
			'time' => date('Y-m-d H:i:s'),
			'ip' => ip_address(),
			'user_agent' => $_SERVER['HTTP_USER_AGENT']
		);
		
		if ( ! $this->user_login_model->insert($user_login_data))
		{
			log_message('error', '用户名'.$username.'登录失败。原因：写入user_login表失败。');
			$this->set_error('登录失败！请与管理员联系！');
			return FALSE;
		}
		
		//将必要的数据写入session
		$this->session->set('user_id', $user_data['id']); //会员ID
		$this->session->set('username', $username); //会员用户名
		$this->session->set('email', $user_data['email']); //会员邮箱
		$this->session->set('ip', ip_address()); //这次登录的IP地址
		
		return TRUE;
	}
	
	//注销
	public function logout()
	{
		$this->session->destroy();
	}
	
	//是否登录
	public function is_login()
	{
		return (boolean)$this->session->get('user_id');
	}
	
	//重置密码（会员ID，原始密码，新密码）
	public function reset_password($user_id, $old_password, $new_password)
	{
		$user_id = intval($user_id);
		$old_password = trim($old_password);
		$new_password = trim($new_password);
		
		//字段验证
		if ($user_id <= 0)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		elseif ($old_password == '')
		{
			$this->set_error('旧密码必须填写！');
			return FALSE;
		}
		elseif (preg_match('/\s+/', $old_password))
		{
			$this->set_error('旧密码错误！');
			return FALSE;
		}
		elseif ($new_password == '')
		{
			$this->set_error('新密码必须填写！');
			return FALSE;
		}
		elseif ( ! preg_match('/^[^\s]{6,20}$/', $password))
		{
			$this->set_error('新密码必须由6-20个非空字符组成！');
			return FALSE;
		}
		
		$user_data = $this->get($user_id, array('username', 'password'));
		
		//账号存在判断
		if ( ! $user_data)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		//旧密码判断
		if ($this->password_hash($old_password) != $user_data['password'])
		{
			$this->set_error('旧密码错误！');
			return FALSE;
		}
		
		$new_password = $this->password_hash($new_password);
		
		if (FALSE === $this->update(array('password' => $password), $user_id))
		{
			log_message('error', '用户名'.$user_data['username'].'重置密码失败。原因：更新user表失败。');
			$this->set_error('重置密码失败！请联系管理员！');
			return FALSE;
		}
		
		return TRUE;
	}
	
	//发送激活邮件（用户ID）
	public function send_activate_email($user_id)
	{
		$user_id = intval($user_id);
		
		if ($user_id <= 0)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		//判断账号是否存在
		$user_data = $this->get($user_id, array('username', 'email'));
		
		if ( ! $user_data)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		//将激活码信息存入表中
		$this->load->model('user_key_model');
		
		$email_key = md5(time().uniqid()); //生成32位字符的激活码
		
		$data = array(
			'user_id' => $user_id,
			'email_key' => $email_key,
			'email_key_time' => time()
		);
		
		if (FALSE === $this->user_key_model->replace($data))
		{
			log_message('error', '用户名'.$user_data['username'].'发送激活邮件失败。原因：写入user_key表失败。');
			$this->set_error('发送激活邮件失败！请联系管理员！');
			return FALSE;
		}
		
		//发送激活邮件
		$this->load->helper('email');
		
		$ci = & get_instance();
		$ci->template->assign('username', $user_data['username']);
		$ci->template->assign('activate_url', site_url('user/activate/'.$user_id.'/'.$email_key));
		$subject = '账号激活';
		$message = $ci->template->fetch('activate_email');
		
		if ( ! send_email($user_data['email'], $subject, $message))
		{
			log_message('error', '用户名'.$username.'发送激活邮件失败。原因：发送邮件失败。');
			$this->set_error('发送激活邮件失败！请联系管理员！');
			return FALSE;
		}
		
		return TRUE;
	}
	
	//发送重置密码邮件（用户ID）
	public function send_reset_password_email($user_id)
	{
		$user_id = intval($user_id);
		
		if ($user_id <= 0)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		//判断账号是否存在
		$user_data = $this->get($user_id, array('username', 'email'));
		
		if ( ! $user_data)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		//将激活码信息存入表中
		$this->load->model('user_key_model');
		
		$email_key = md5(time().uniqid()); //生成32位字符的激活码
		
		$data = array(
			'user_id' => $user_id,
			'email_key' => $email_key,
			'email_key_time' => time()
		);
		
		if (FALSE === $this->user_key_model->replace($data))
		{
			log_message('error', '用户名'.$user_data['username'].'发送重置密码邮件失败。原因：写入user_key表失败。');
			$this->set_error('发送重置密码邮件失败！请联系管理员！');
			return FALSE;
		}
		
		//发送重置密码邮件
		$this->load->helper('email');
		
		$ci = & get_instance();
		$ci->template->assign('username', $user_data['username']);
		$ci->template->assign('reset_password_url', site_url('user/reset_password/'.$user_id.'/'.$email_key));
		$subject = '账号激活';
		$message = $ci->template->fetch('reset_password_email');
		
		if ( ! send_email($user_data['email'], $subject, $message))
		{
			log_message('error', '用户名'.$username.'发送重置密码邮件失败。原因：发送邮件失败。');
			$this->set_error('发送重置密码邮件失败！请联系管理员！');
			return FALSE;
		}
		
		return TRUE;
	}
	
	//激活（会员ID，激活码，激活类型email or phone）
	public function activate($user_id, $key, $type = 'email')
	{
		$user_id = intval($user_id);
		$key = trim($key);
		$type = ($type == 'email') ? 'email' : 'phone';
		
		//字段验证
		if ($user_id <= 0)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		elseif ($key == '' || ! preg_match('/^[a-z0-9]{32}$/i', $key))
		{
			$this->set_error('激活码错误！');
			return FALSE;
		}
		
		$user_data = $this->get($user_id, array('username'));
		
		if ( ! $user_data)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		$this->load->model('user_key_model');
		
		$fields = array($type.'_key', $type.'_key_time');
		
		$user_key_data = $this->user_key_model->get_one(array('user_id' => $user_id), $fields);
		
		//激活码验证
		if ( ! $user_key_data)
		{
			$this->set_error('激活码不存在！');
			return FALSE;
		}
		elseif ($user_key_data[$type.'_key'] != $key)
		{
			$this->set_error('激活码错误！');
			return FALSE;
		}
		elseif ($user_key_data[$type.'_key_time'] < (time() - 86400))
		{
			$this->set_error('激活码已经过期！');
			return FALSE;
		}
		
		if (FALSE === $this->update(array('activated' => 1), $user_id))
		{
			log_message('error', '用户名'.$user_data['username'].'激活失败。原因：更新user表失败！');
			$this->set_error('激活失败！请联系管理员！');
			return FALSE;
		}
		
		return TRUE;
	}
	
	//禁用账号（会员ID，禁用原因）
	public function banned($user_id, $banned_reason = '')
	{
		$user_id = intval($user_id);
		$banned_reason = trim($banned_reason);
		
		if ($user_id <= 0)
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		if ( ! $this->exists($user_id))
		{
			$this->set_error('账号不存在！');
			return FALSE;
		}
		
		$data = array(
			'banned' => 1,
			'banned_reason' => $banned_reason
		);
		
		if (FALSE === $this->update($data, $user_id))
		{
			log_message('error', '用户名'.$user_data['username'].'禁用失败。原因：更新user表失败！');
			$this->set_error('禁用账号失败！请联系管理员！');
			return FALSE;
		}
		
		return TRUE;
	}
	
	//返回加密密码
	public function password_hash($password)
	{
		return md5(md5($password) + $this->password_key);
	}
	
	//返回用户名是否可注册，可用TRUE，不可用FALSE
	public function is_username_available($username)
	{
		$condition = array(
			'username' => $username
		);
		
		return $this->exists($condition) ? FALSE : TRUE;
	}
	
	//返回邮箱是否可注册，可用TRUE，不可用FALSE
	public function is_email_available($email)
	{
		$condition = array(
			'email' => $email
		);
		
		return $this->exists($condition) ? FALSE : TRUE;
	}
	
}